<?php
class GridControl extends BaseViewControl
{
	protected $viewName;
    protected $displayValues;
    protected $noFilter = false;
    protected $renderStub = true;
    protected $cssClass = 'gridcontrol hashable';
    protected $cssFile = 'grid';
    protected $jsClass = 'GridControl';
    protected $resourceId = 'SystemResource';
    protected $params = array();

	public function GridControl($view_name = null, $name = null)
	{
        if ($view_name) $this->viewName = $view_name;
        if (!$this->viewName) $this->viewName = RequestHandler::Get('view_id');
        if (!$name) $name = $this->viewName;
        $this->renderStub = RequestHandler::IsExisted('stub') ? RequestHandler::Get('stub') : $this->renderStub;
        $params = RequestHandler::Get('param');
        if (is_array($params)) $this->params = array_merge($this->params, $params);
        parent::__construct($name);
	}

    protected function GetRefreshUrl()
    {
        return parent::GetRefreshUrl().FS.$this->viewName.FS.$this->name.'&stub=0';
    }

    protected function ProcessRequest()
    {
        return $this->Render();
    }

    protected function LoadView()
    {
        $this->view = new Grid($this->viewName);
    }

    public static function GetInstance($view_name, $name = null)
    {
        if (VmViewModel::GetInstance()->IsTree($view_name))
            return new GridTreeControl($view_name, $name);
        else
            return new GridControl($view_name, $name);
    }

    public function GetConfig()
    {
        return GridConfig::GetInstance();
    }

    public function SortBy($field, $order = 'asc')
	{
        $_REQUEST['sort'] = $field;
        $_REQUEST['order'] = strtolower($order);
	}

    public function RenderStub()
    {
        $states = $this->GetStubStates();
        $refresh_url = $this->GetRefreshUrl();
        $js = $this->GetJsScript();
        return "<div class='stub {$this->cssClass}' id='{$this->name}' url='$refresh_url'>$states</div>$js";
    }

	public function Render()
	{
        if ($this->renderStub) return $this->RenderStub();

        $this->view->Refresh();
	    $dir_elements = GridConfig::GetInstance()->DIR_HTML_CONTROLS.DS.'grid';
        $this->ReplaceElement('footer', $dir_elements);
        $this->ReplaceElement('grid_list', $dir_elements);
        $enabledFields = $this->view->GetEnabledFields();
        $colspan = count($enabledFields) + 2;
    	$this->Replace(array(
			'css_class' 	=> $this->cssClass,
			'view_id' 	    => $this->view->id,
			'record_count' 	=> $this->view->recordCount,
			'page_count'	=> $this->view->pageCount,
            'sort'          => $this->view->sort,
            'order'         => $this->view->order,
			'page_select' 	=> $this->GetPager(),
			'rpp_select' 	=> $this->GetRppSelect(),
			'mass_actions' 	=> $this->GetMassActions(),
			'norecord' 		=> $this->GetNoRecordMessage(),
			'addnew_button' => $this->GetAddNewButton(),
            'hidden_filter' => $this->GetHiddenFilterBoxes(),
            'params'        => $this->GetParamBoxes(),
            'hidden_edit'   => $this->GetHiddenEditBoxes(),
            'nodes_state'   => $this->GetNodeStates(),
            'colspan'       => $colspan,
            'js_script'     => $this->GetJsScript(),
		));

    	$this->Repeat('column', $enabledFields, array($this, 'FormatColumn'));
    	$this->Replace($this->GetEditBoxes());
    	$this->Replace($this->GetFilterBoxes());
    	$this->Replace($this->GetListBoxes());
    	$this->RepeatRow();
        $this->Replace(RequestHandler::GetFilter());
        return parent::Render();
	}

    protected function GetNodeStates()
    {}

    protected function GetNoRecordMessage()
    {
        return empty($this->view->data) ? '<tr><td colspan="100" style="font-size:150%">No record found</td></tr>' : null;
    }

    protected function GetRppSelect()
	{
        $drop = new SelectControl('limit', Set::SelfCombine(GridConfig::GetInstance()->PAGER), $this->view->rpp);
        return $drop->Render();
	}

    protected function GetPager()
	{
		$page = $this->view->page;
        $pages = $this->GetPages();
        $drop = new SelectControl('page', Set::SelfCombine($pages), $page);
        $drop->AddCssClass('page');
		return $drop->Render();
	}

    protected function GetPages()
    {
        $page = $this->view->page;
        $count = $this->view->pageCount;
        if ($count > 500)
        {
            $low = $page - 10;
            $hight = $page+10;
            if ($low < 0) $low = 1;
            if ($hight > $count) $hight = $count;
            $middle_range = range($low, $hight, 1);


            $low = $step = 50;
            $offset = $count % $step;
            $hight = $count - $offset;
            $range = range($low, $hight, $step);

            $pages = array_merge(array(1=>1), $range, $middle_range, array($count=>$count));
            sort($pages, SORT_NUMERIC);
        }
        else
            $pages = range(1, $count);
        return $pages;
    }

    protected function GetHiddenFilterBoxes()
	{
		$boxes = null;
        foreach ($this->view->filter as $field_name => $value)
		{
			if ($this->IsHiddenFilter($field_name))
				$boxes .= $this->GetHiddenFilterBox($field_name, $value);
		}
		return "<div class='hiddenFilters'>$boxes</div>";
	}

    protected function GetParamBoxes()
    {
        $boxes = null;
        foreach ($this->params as $key => $value)
        {
            $boxes .= $this->GetParamBox($key, $value);
        }
        return $boxes;
    }

    protected function GetParamBox($key, $value)
    {
        return "<input class='nohash' name='param[$key]' value='$value' type='hidden' />";
    }

    public function SetParam($key, $value)
    {
        $this->params[$key] = $value;
    }

    protected function GetHiddenEditBoxes()
    {
        $boxes = null;
        foreach ($this->view->filter as $field_name => $value)
        {
            if (!$this->IsEnabled($field_name))
                $boxes .= $this->GetHiddenEditBox($field_name, $value);
        }
        return $boxes;
    }

    protected function GetHiddenEditBox($field_name, $value)
    {
        $model_name = $this->view->GetModelName();
        return "<div class='cell editable edit-$field_name hidden' field='$field_name' value='$value'><input class='box' type='hidden' name='{$model_name}[#id][$field_name]' value='#v'/></div>";
    }

    protected function IsEnabled($field_name)
    {
        return $this->view->GetField($field_name)->enabled;
    }

    protected function IsHiddenFilter($field_name)
    {
        $field = $this->view->GetField($field_name);
        return $field->hiddenFilter || (!$field->enabled && $field->isFilterable);
    }

    protected function GetStubStates()
	{
		$boxes = null;
        $filters = RequestHandler::GetFilter();
        foreach ($filters as $field_name => $value)
        {
            $boxes .= $this->GetHiddenFilterBox($field_name, $value);
        }

        $sort = RequestHandler::Get('sort');
		if ($sort)
		{
            $order = RequestHandler::Get('order');
            if (!$order) $order = 'asc';
			$boxes .= "<input name='sort' type='hidden' value='$sort' /><input name='order' type='hidden' value='$order' />";
		}

        $request = $this->GetParamBoxes();
		return $boxes.$request.$this->GetNodeStates();
	}

    protected function RepeatRow()
	{
    	$this->Repeat('row', $this->view->data, array($this, 'FormatRow'));
	}

	public function FormatColumn($field)
	{
        $item = parent::FormatColumn($field);
        $item['header_class'] = $this->GetHeaderClass($field);
        $item['style'] = $this->GetCssStyle($field);
        $item['css_column'] = $this->GetCssColumn($field);
    	return $item;
	}

    protected function GetCssStyle($field)
    {
        return $field->width ? "width:{$field->width}px" : null;
    }

	public function FormatRow($item, $level = null)
	{
		foreach($this->view->GetEnabledFields() as $field_name => $field)
		{
        	$item["formated-$field_name"] = $this->GetFieldFormated($item[$field_name], $field, $item, $level);
        	$item["nowrap-$field_name"] = $this->GetNowrap($item[$field_name], $field);
		}
        $item['actions_box'] = $this->RenderActions($this->GetActions(), $item);
        $item['item_key'] = $this->GetKey($item);
        $item['css_selected'] = $this->GetCssRow($item);
        $item['row_style'] = $this->GetStyleRow($item);
        $item['css_column_row'] = $this->GetCssColumnRow($item);
        $item['checked'] = $this->GetCheked($item);
		return $item;
	}

    public function GetCssRow($row)
	{
        $id = $this->GetKey($row);
        return $this->GetCssSelected($id);
	}

    protected function GetCssColumn($field)
    {
        return null;
    }

    public function GetCssColumnRow($row)
    {
        return null;
    }

    public function GetStyleRow($row)
    {
        return null;
    }

    public function GetCssSelected($id)
    {
        return $this->IsSelected($id) ? 'selected' : null;
    }

    public function GetCheked($row)
	{
        $id = $this->GetKey($row);
		return $this->IsSelected($id) ? 'checked="checked"' : null;
	}

    protected function IsSelected($id)
	{
        if (is_object($id)) $id = (string) $id;
        $selected = RequestHandler::Get('selected');
		return $selected && array_key_exists($id, $selected);
	}

	public function GetEscapedValue($value, $field)
	{
		return $field->IsString() && !$field->IsHTML() ? htmlentities($value) : $value;
	}

	protected function GetHeaderClass($field)
	{
		$class = $field->isSortable ? ' sortable' : null;
		if ($field->isSortable)
			$class .= $field->name == $this->view->sort ? ' sort '.$this->view->order : null;
		return $class;
	}

	public function RenderActions($actions, $row)
	{
        $id = $this->GetKey($row);
		$output = null;
		foreach ($actions as $action)
		{
			$output .= str_replace('[:id:]', $id, $action['code']);
		}
		return $output;
	}

	protected function GetFilterBoxes()
	{
    	$boxes = array();
    	foreach ($this->view->GetEnabledFields() as $field_name => $field)
    	{
    		$nofilter = !$field->isFilterable || $this->noFilter;

    		$boxes["filter-$field_name"] = $nofilter ? null : $this->GetFilterBox($field);
    		$boxes["filter_caption-$field_name"] = $nofilter ? null : $field->caption;
    	}
        return $boxes;
	}

	protected function GetListBoxes()
	{
    	$boxes = array();
        $renderlist = RequestHandler::Get('renderlist');
    	foreach ($this->view->GetEnabledFields() as $field_name => $field)
    	{
            $boxes["gridlist-$field_name"] = $renderlist ? null : $this->GetGridlist($field);
    	}
        return $boxes;
	}

    protected function GetGridlist($field)
	{
    	if ($field->formatType == VmConfig::GetInstance()->FIELDTYPE_GRID_SELECT)
    	{
			$field_name = $field->name;
            $model_name = String::Pascalize($field->foreignKey->table);
			$view_select = $model_name.'Select';

            if (!VmViewModel::GetInstance()->IsExisted($view_select))
                return null;

	        $gl = new GridListControl($view_select, "{$this->name}_$field_name", $field->refField);
	        return '<div>'.$gl->RenderStub().'</div>';
    	}
    	return null;
	}

    protected function GetFilterBox($field)
	{
		$field_name = $field->name;
    	$value = isset($this->view->filter[$field_name]) ? $this->view->filter[$field_name] : null;
    	$disabled = $field->isFilterable ? null : 'disabled="disabled"';

        if ($field->IsBool())
		{
			$options = SelectControl::GetOptions(array(1=>'True', 0=>'False'), $value);
			return "<select $disabled name='filter[$field_name]' class='box elastic'>$options</select>";
		}

		switch ($field->formatType)
		{
			case VmConfig::GetInstance()->FIELDTYPE_SELECT:
			case VmConfig::GetInstance()->FIELDTYPE_TREE_SELECT:
				$options = SelectControl::GetOptions($field->selectList, $value);
				$box = "<select $disabled name='filter[$field_name]' class='box elastic'>$options</select>";
				break;
			case VmConfig::GetInstance()->FIELDTYPE_DATEPICKER:
    			$box = "<div class='boxwrapper'><input $disabled autocomplete='off' class='box elastic daterange_picker' name='filter[$field_name]' value='$value' /></div>";
				break;
			case VmConfig::GetInstance()->FIELDTYPE_GRID_SELECT:
				$display = $this->GetSelectedDisplay($field, $value);
				$box = "<div class='boxwrapper nomargin'><input $disabled name='filter[$field_name]' class='box gridselect' drop='{$this->name}_$field_name' value='$value' display='$display' /></div>";
				break;
			default:
    			$box = "<div class='boxwrapper'><input $disabled class='box elastic' name='filter[$field_name]' value='$value' /></div>";
				break;
		}

    	return $box;
	}

    protected function GetHiddenFilterBox($field_name, $value)
	{
		return "<div class='filter field-$field_name'><input name='filter[$field_name]' value='$value' type='hidden' class='box nohash' /></div>";
	}

	protected function GetAddNewButton()
	{
		$url_base_imgages = BaseConfig::GetInstance()->URL_IMG;
		return $this->view->allowInsert ? "<span class='add_new action_item'>Add</span>" : null;
	}

	public function GetMassActions()
	{
		$mass_actions = array();
		if ($this->view->allowEdit)
            $mass_actions[]['code'] = "<span class='toogle_edit action_item'>Toggle edit</span>";

		if ($this->view->allowDelete)
            $mass_actions[]['code'] = "<span class='mass_action action_item' action='Delete'>Delete</span>";

		$mass_actions = array_merge($mass_actions, $this->view->GetMassActions());

		$mass_actions = Set::Pluck($mass_actions, 'code');
		if (!empty($mass_actions))
			return '- '. implode(', ', $mass_actions);
		return null;
	}

	protected function GetActions()
	{
		$actions = array();
		if ($this->view->allowEdit)
            $actions[]['code'] = '<div class="action_item inline_edit">Edit</div>';

		if ($this->view->allowDelete)
            $actions[]['code'] = '<div class="action_item delete">Delete</div>';

	    foreach ($this->view->GetActions() as $key=>$act)
		{
			$actions[]['code'] = "<div class='action_item'>{$act['code']}</div>";
		}
		return $actions;
	}

    public function GetData()
    {
        return $this->view->data;
    }

    protected function GetFilter($field_name)
    {
        $filter = RequestHandler::GetFilter();
        return isset($filter[$field_name]) ? $filter[$field_name] : null;
    }

    public function SetRenderStub($value)
    {
        $this->renderStub = $value;
    }
}
?>